package staff.io;

import static staff.util.XmlUtils.XML_EMPLOYE_TAG;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import staff.logic.Employee;

/** Class for loading employes from XML. SAX used. */
public class SAXEmployeLoader extends DefaultHandler implements EmployeLoader {
    private Queue<Employee> employeQueue = new LinkedList<Employee>();

    /** Constructor */
    public SAXEmployeLoader(String fileName)
            throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory spFactory = SAXParserFactory.newInstance();
        spFactory.setValidating(false);
        SAXParser saxParser = spFactory.newSAXParser();
        XMLReader xmlReader = saxParser.getXMLReader();
        xmlReader.setContentHandler(new SAXEmployeContentHandler());
        InputSource source = new InputSource(fileName);
        xmlReader.parse(source);
    }

    public boolean hasNext() {
        return !employeQueue.isEmpty();
    }

    public Employee loadNext() {
        if (hasNext()) {
            return employeQueue.remove();
        } else {
            throw new IllegalStateException("There is no more employe to load.");
        }
    }

    public void close() {
        // it seems like nothing need to close here
    }

    /** SAX employe content handler */
    private class SAXEmployeContentHandler extends DefaultHandler {
        Employee employe;
        Employee.FieldTag fieldTag;
        StringBuilder fieldValue = new StringBuilder();

        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
            // if current element is employe then create new employe
            if (qName.equals(XML_EMPLOYE_TAG)) {
                employe = new Employee();
            }
            // check that current element is some employe field
            if (Employee.FieldTag.containsName(qName)) {
                fieldTag = Employee.FieldTag.valueOf(qName);
                fieldValue.delete(0, fieldValue.length()); // reset for new
                                                            // field
            }
        }

        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            // if current element is employe field then save field info
            if (fieldTag != null) {
                fieldValue.append(ch, start, length);
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            // if current element is employe then save employe to result queue
            if (qName.equals(XML_EMPLOYE_TAG)) {
                employeQueue.add(employe);
                employe = null;
            }
            // if current element is employe field then set field value to
            // employe
            if (employe != null && fieldTag != null && fieldValue.length() > 0) {
                employe.setParamByName(fieldTag.toString(),
                        fieldValue.toString());
            }
            fieldTag = null; // current element is ended, reset field tag
        }

    }

}
